"""Test media source helpers."""

from unittest.mock import Mock, patch

import pytest

from homeassistant.components import media_source
from homeassistant.components.media_player import BrowseError
from homeassistant.components.media_source import const, models
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component


async def test_async_browse_media(hass: HomeAssistant) -> None:
    """Test browse media."""
    assert await async_setup_component(hass, media_source.DOMAIN, {})
    await hass.async_block_till_done()

    # Test non-media ignored (/media has test.mp3 and not_media.txt)
    media = await media_source.async_browse_media(hass, "")
    assert isinstance(media, media_source.models.BrowseMediaSource)
    assert media.title == "media"
    assert len(media.children) == 2

    # Test content filter
    media = await media_source.async_browse_media(
        hass,
        "",
        content_filter=lambda item: item.media_content_type.startswith("video/"),
    )
    assert isinstance(media, media_source.models.BrowseMediaSource)
    assert media.title == "media"
    assert len(media.children) == 1, media.children
    media.children[0].title = "Epic Sax Guy 10 Hours"
    assert media.not_shown == 1

    # Test content filter adds to original not_shown
    orig_browse = models.MediaSourceItem.async_browse

    async def not_shown_browse(self):
        """Patch browsed item to set not_shown base value."""
        item = await orig_browse(self)
        item.not_shown = 10
        return item

    with patch(
        "homeassistant.components.media_source.models.MediaSourceItem.async_browse",
        not_shown_browse,
    ):
        media = await media_source.async_browse_media(
            hass,
            "",
            content_filter=lambda item: item.media_content_type.startswith("video/"),
        )
    assert isinstance(media, media_source.models.BrowseMediaSource)
    assert media.title == "media"
    assert len(media.children) == 1, media.children
    media.children[0].title = "Epic Sax Guy 10 Hours"
    assert media.not_shown == 11

    # Test invalid media content
    with pytest.raises(BrowseError):
        await media_source.async_browse_media(hass, "invalid")

    # Test base URI returns all domains
    media = await media_source.async_browse_media(hass, const.URI_SCHEME)
    assert isinstance(media, media_source.models.BrowseMediaSource)
    assert len(media.children) == 1
    assert media.children[0].title == "My media"


async def test_async_resolve_media(hass: HomeAssistant) -> None:
    """Test browse media."""
    assert await async_setup_component(hass, media_source.DOMAIN, {})
    await hass.async_block_till_done()

    media = await media_source.async_resolve_media(
        hass,
        media_source.generate_media_source_id(media_source.DOMAIN, "local/test.mp3"),
        None,
    )
    assert isinstance(media, media_source.models.PlayMedia)
    assert media.url == "/media/local/test.mp3"
    assert media.mime_type == "audio/mpeg"


async def test_async_resolve_media_no_entity(
    hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None:
    """Test browse media."""
    assert await async_setup_component(hass, media_source.DOMAIN, {})
    await hass.async_block_till_done()

    with pytest.raises(RuntimeError):
        await media_source.async_resolve_media(
            hass,
            media_source.generate_media_source_id(
                media_source.DOMAIN, "local/test.mp3"
            ),
        )


async def test_async_unresolve_media(hass: HomeAssistant) -> None:
    """Test browse media."""
    assert await async_setup_component(hass, media_source.DOMAIN, {})
    await hass.async_block_till_done()

    # Test no media content
    with pytest.raises(media_source.Unresolvable):
        await media_source.async_resolve_media(hass, "", None)

    # Test invalid media content
    with pytest.raises(media_source.Unresolvable):
        await media_source.async_resolve_media(hass, "invalid", None)

    # Test invalid media source
    with pytest.raises(media_source.Unresolvable):
        await media_source.async_resolve_media(
            hass, "media-source://media_source2", None
        )


async def test_browse_resolve_without_setup() -> None:
    """Test browse and resolve work without being setup."""
    with pytest.raises(BrowseError):
        await media_source.async_browse_media(Mock(data={}), None)

    with pytest.raises(media_source.Unresolvable):
        await media_source.async_resolve_media(Mock(data={}), None, None)
